#pragma once

#include <string>

#if defined(__linux__)
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#elif defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
#include <direct.h>
#endif

/* declare */
namespace os {
    namespace path {
        bool exists(const std::string& path);
        std::string dirname(const std::string& path);
        std::string basename(const std::string& path);
        
        // 基础版本：连接两个路径
        std::string join(const std::string& a, const std::string& b);
        
        // 可变参数模板版本：支持任意数量的路径参数
        template<typename... Args>
        std::string join(const std::string& first, const std::string& second, Args... args);
        
        // 获取绝对路径
        std::string abspath(const std::string& path);
        
        // 检查是否为目录
        bool isdir(const std::string& path);
        
        // 检查是否为普通文件
        bool isfile(const std::string& path);
    }
}

/* define */
namespace os {
    namespace path {
        bool exists(const std::string& path) {
            // 判断操作系统，只有 Linux 和 Windows 支持标准库中的文件/文件夹存在检查
#if defined(__linux__)
            // Linux 下使用 stat 函数获取文件/文件夹信息
            struct stat buffer;
            return (stat(path.c_str(), &buffer) == 0);  // 若调用成功则返回 true，否则返回 false
#elif defined(_WIN32) || defined(_WIN64)
            // Windows 下使用 GetFileAttributesA 函数获取文件/文件夹属性
            DWORD attributes = GetFileAttributesA(path);
            return (attributes != INVALID_FILE_ATTRIBUTES);  // 若调用成功则返回 true，否则返回 false
#else
            // 不支持的系统，抛出异常
            throw Exception("This function does not support the operating系统");
#endif
        }
        
        std::string dirname(const std::string& path) {
            if (path.empty()) {
                return ".";
            }
            
            // 查找最后一个路径分隔符
            size_t pos = path.find_last_of("/\\");
            
            if (pos == std::string::npos) {
                // 没有找到路径分隔符，返回当前目录
                return ".";
            } else if (pos == 0) {
                // 分隔符在开头，返回根目录
                return path.substr(0, 1);
            } else {
                // 返回分隔符之前的路径
                return path.substr(0, pos);
            }
        }
        
        std::string basename(const std::string& path) {
            if (path.empty()) {
                return ".";
            }
            
            // 查找最后一个路径分隔符
            size_t pos = path.find_last_of("/\\");
            
            if (pos == std::string::npos) {
                // 没有找到路径分隔符，返回整个路径
                return path;
            } else {
                // 返回分隔符之后的部分
                return path.substr(pos + 1);
            }
        }
        
        std::string join(const std::string& a, const std::string& b) {
            if (a.empty()) {
                return b;
            }
            
            if (b.empty()) {
                return a;
            }
            
            // 检查a是否以路径分隔符结尾
            bool aEndsWithSeparator = !a.empty() && (a.back() == '/' || a.back() == '\\');
            // 检查b是否以路径分隔符开头
            bool bStartsWithSeparator = !b.empty() && (b.front() == '/' || b.front() == '\\');
            
            if (aEndsWithSeparator || bStartsWithSeparator) {
                return a + b;
            } else {
                return a + "/" + b;
            }
        }
        
        // 可变参数模板实现
        template<typename... Args>
        std::string join(const std::string& first, const std::string& second, Args... args) {
            // 递归调用：先连接前两个路径，然后与剩余参数继续连接
            return join(join(first, second), args...);
        }
        
        std::string abspath(const std::string& path) {
            if (path.empty()) {
                return path;
            }
            
            // 检查是否已经是绝对路径
            // Linux下绝对路径以'/'开头，Windows下以'[盘符]:'开头
#if defined(__linux__)
            if (path.front() == '/') {
                return path;
            }
#elif defined(_WIN32) || defined(_WIN64)
            // Windows绝对路径判断：以盘符开头（如C:）或者以'\'开头
            if (path.size() >= 2 && path[1] == ':' && 
                ((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z'))) {
                return path;
            }
            if (path.front() == '\\' || path.front() == '/') {
                return path;
            }
#endif
            
            // 获取当前工作目录
            std::string cwd;
            
#if defined(__linux__)
            char buffer[PATH_MAX];
            if (getcwd(buffer, sizeof(buffer)) != nullptr) {
                cwd = std::string(buffer);
            }
#elif defined(_WIN32) || defined(_WIN64)
            char buffer[MAX_PATH];
            if (_getcwd(buffer, sizeof(buffer)) != nullptr) {
                cwd = std::string(buffer);
            }
#endif
            
            // 如果获取当前目录失败，返回原路径
            if (cwd.empty()) {
                return path;
            }
            
            // 连接当前目录和相对路径
            return os::path::join(cwd, path);
        }
        
        bool isdir(const std::string& path) {
            if (path.empty()) {
                return false;
            }
            
            // 检查路径是否存在
            if (!os::path::exists(path)) {
                return false;
            }
            
#if defined(__linux__)
            // Linux 下使用 stat 函数获取文件/文件夹信息
            struct stat buffer;
            if (stat(path.c_str(), &buffer) == 0) {
                // 使用 S_ISDIR 宏检查是否为目录
                return S_ISDIR(buffer.st_mode);
            }
            return false;
#elif defined(_WIN32) || defined(_WIN64)
            // Windows 下使用 GetFileAttributesA 函数获取文件/文件夹属性
            DWORD attributes = GetFileAttributesA(path.c_str());
            if (attributes != INVALID_FILE_ATTRIBUTES) {
                // 检查是否包含 DIRECTORY 属性
                return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
            }
            return false;
#else
            // 不支持的系统
            return false;
#endif
        }
        
        bool isfile(const std::string& path) {
            if (path.empty()) {
                return false;
            }
            
            // 检查路径是否存在
            if (!os::path::exists(path)) {
                return false;
            }
            
#if defined(__linux__)
            // Linux 下使用 stat 函数获取文件/文件夹信息
            struct stat buffer;
            if (stat(path.c_str(), &buffer) == 0) {
                // 使用 S_ISREG 宏检查是否为普通文件
                return S_ISREG(buffer.st_mode);
            }
            return false;
#elif defined(_WIN32) || defined(_WIN64)
            // Windows 下使用 GetFileAttributesA 函数获取文件/文件夹属性
            DWORD attributes = GetFileAttributesA(path.c_str());
            if (attributes != INVALID_FILE_ATTRIBUTES) {
                // 检查是否不包含 DIRECTORY 属性（即为文件）
                return (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
            }
            return false;
#else
            // 不支持的系统
            return false;
#endif
        }
    }
}